1   /*
2    * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.
8    *
9    * This code is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12   * version 2 for more details (a copy is included in the LICENSE file that
13   * accompanied this code).
14   *
15   * You should have received a copy of the GNU General Public License version
16   * 2 along with this work; if not, write to the Free Software Foundation,
17   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18   *
19   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20   * or visit www.oracle.com if you need additional information or have any
21   * questions.
22   */
23  
24  /* @test
25   * @bug 4287596
26   * @summary Unit test for "Pluggable Connectors and Transports" feature.
27   *
28   * This test checks that VirtualMachineManager creates Connectors that
29   * are "compatible" those created by 1.4 or earilier releases.
30   */
31  
32  import com.sun.jdi.*;
33  import com.sun.jdi.connect.*;
34  import java.util.*;
35  
36  public class CompatibleConnectors {
37  
38      // number of tests that fail
39      static int failures;
40  
41      static void fail(String msg) {
42          System.out.println(msg + " - test failed.");
43          failures++;
44      }
45  
46      // the AttachingConnectors that we expect
47      static Object[][] attachingConnectors() {
48          return new Object[][] {
49              { "com.sun.jdi.SocketAttach",
50                "dt_socket",
51                new String[] { "hostname", "Connector.StringArgument", "false" },
52                new String[] { "port",     "Connector.IntegerArgument", "true" }
53              },
54  
55              { "com.sun.jdi.SharedMemoryAttach",
56                "dt_shmem",
57                new String[] { "name", "Connector.StringArgument", "true" }
58              }
59          };
60      }
61  
62      // the ListeningConnectors that we expect
63      static Object[][] listeningConnectors() {
64          return new Object[][] {
65              { "com.sun.jdi.SocketListen",
66                "dt_socket",
67                new String[] { "port", "Connector.IntegerArgument", "true" }
68              },
69  
70              { "com.sun.jdi.SharedMemoryListen",
71                "dt_shmem",
72                new String[] { "name", "Connector.StringArgument", "false" }
73              }
74          };
75  
76      }
77  
78      // the LaunchingConnectors that we expect
79      // - note that we don't indicate the transport name (as it varies
80      // for these connectors)
81      static Object[][] launchingConnectors() {
82          return new Object[][] {
83              { "com.sun.jdi.CommandLineLaunch",
84                null,
85                new String[] { "home",    "Connector.StringArgument",     "false" },
86                new String[] { "options", "Connector.StringArgument",     "false" },
87                new String[] { "main",    "Connector.StringArgument",     "true"  },
88                new String[] { "suspend", "Connector.BooleanArgument",    "false" },
89                new String[] { "quote",   "Connector.StringArgument",     "true"  },
90                new String[] { "vmexec",  "Connector.StringArgument",     "true" }
91              },
92  
93              { "com.sun.jdi.RawCommandLineLaunch",
94                null,
95                new String[] { "command",  "Connector.StringArgument",     "true" },
96                new String[] { "address",  "Connector.StringArgument",     "true" },
97                new String[] { "quote",    "Connector.StringArgument",     "true" }
98              }
99          };
100 
101     }
102 
103     // find Connector by name, return null if not found
104     static Connector find(String name, List l) {
105         Iterator i = l.iterator();
106         while (i.hasNext()) {
107             Connector c = (Connector)i.next();
108             if (c.name().equals(name)) {
109                 return c;
110             }
111         }
112         return null;
113     }
114 
115     // check that a connector is of the expected type
116     static void type_match(String arg_name, String arg_type, Connector.Argument arg) {
117         boolean fail = false;
118         if (arg_type.equals("Connector.StringArgument")) {
119             if (!(arg instanceof Connector.StringArgument)) {
120                 fail = true;
121             }
122         }
123         if (arg_type.equals("Connector.IntegerArgument")) {
124             if (!(arg instanceof Connector.IntegerArgument)) {
125                 fail = true;
126             }
127         }
128         if (arg_type.equals("Connector.BooleanArgument")) {
129             if (!(arg instanceof Connector.BooleanArgument)) {
130                 fail = true;
131             }
132         }
133         if (arg_type.equals("Connector.SelectedArgument")) {
134             if (!(arg instanceof Connector.IntegerArgument)) {
135                 fail = true;
136             }
137         }
138         if (fail) {
139             fail(arg_name + " is of type: " + arg.getClass() + ", expected: "
140                  + arg_type);
141         }
142     }
143 
144 
145     // check that a Connector is compatible
146     static void check(Object[] desc, Connector connector) {
147         String name = (String)desc[0];
148         String transport_name = (String)desc[1];
149 
150         // if the transport name is "null" it means its transport may
151         // vary (eg: SunCommandLineLauncher will choose shared memory
152         // on Windows and dt_socket on Solaris). In that case we can't
153         // check the transport name.
154         //
155         if (transport_name != null) {
156             System.out.println("Checking transpot name");
157             if (!(transport_name.equals(connector.transport().name()))) {
158                 fail("transport().name() returns: " +
159                     connector.transport().name() + ", expected: " + transport_name);
160             }
161         }
162 
163         // check that all the old arguments still exist
164         for (int i=2; i<desc.length; i++) {
165             String[] args = (String[])desc[i];
166             String arg_name = args[0];
167             String arg_type = args[1];
168             String arg_mandatory = args[2];
169 
170             System.out.println("Checking argument: " + arg_name);
171 
172             // check that the arg still exists
173             Map defaultArgs = connector.defaultArguments();
174             Object value = defaultArgs.get(arg_name);
175             if (value == null) {
176                 fail(name + " is missing Connector.Argument: " + arg_name);
177                 continue;
178             }
179 
180             // next check that the type matches
181             Connector.Argument connector_arg = (Connector.Argument)value;
182 
183             // check that the argument type hasn't changed
184             type_match(arg_name, arg_type, connector_arg);
185 
186             // check that an optional argument has been made mandatory
187             if (arg_mandatory.equals("false")) {
188                 if (connector_arg.mustSpecify()) {
189                     fail(arg_name + " is now mandatory");
190                 }
191             }
192         }
193 
194         // next we check for new arguments that are mandatory but
195         // have no default value
196 
197         System.out.println("Checking for new arguments");
198         Map dfltArgs = connector.defaultArguments();
199         Iterator iter = dfltArgs.keySet().iterator();
200         while (iter.hasNext()) {
201             String arg_name = (String)iter.next();
202 
203             // see if the argument is new
204             boolean found = false;
205             for (int j=2; j<desc.length; j++) {
206                 String[] args = (String[])desc[j];
207                 if (args[0].equals(arg_name)) {
208                     found = true;
209                     break;
210                 }
211             }
212 
213             if (!found) {
214                 Connector.Argument connector_arg =
215                     (Connector.Argument)dfltArgs.get(arg_name);
216 
217                 if (connector_arg.mustSpecify()) {
218                     String value = connector_arg.value();
219                     if (value.equals("")) {
220                         value = null;
221                     }
222                     if (value == null) {
223                         fail("New Connector.Argument \"" + connector_arg.name() +
224                             "\" added - argument is mandatory");
225                     }
226                 }
227             }
228         }
229     }
230 
231 
232     // compare the actual list of Connectors against the
233     // expected list of Connectors.
234     static void compare(Object[][] prev, List list) {
235         String os = System.getProperty("os.name");
236         for (int i=0; i<prev.length; i++) {
237             Object[] desc = prev[i];
238             String name = (String)desc[0];
239 
240             // ignore Windows specific Connectors are non-Windows machines
241             if (!(os.startsWith("Windows"))) {
242                 if (name.equals("com.sun.jdi.SharedMemoryAttach") ||
243                     name.equals("com.sun.jdi.SharedMemoryListen")) {
244                     continue;
245                 }
246             }
247 
248             System.out.println("");
249             System.out.println("Checking Connector " + name);
250 
251             // check that the Connector exists
252             Connector c = find(name, list);
253             if (c == null) {
254                 fail("Connector is missing");
255                 continue;
256             }
257 
258             check(desc, c);
259         }
260     }
261 
262     public static void main(String args[]) throws Exception {
263         VirtualMachineManager vmm = Bootstrap.virtualMachineManager();
264 
265         // in 1.2/1.3/1.4 the defualtConnector was
266         // com.sun.jdi.CommandLineLaunch. Many debuggers probably
267         // depend on this so check that it's always the default.
268         //
269         String expected = "com.sun.jdi.CommandLineLaunch";
270         System.out.println("Checking that defaultConnector is: " + expected);
271         String dflt = vmm.defaultConnector().name();
272         if (!(dflt.equals(expected))) {
273             System.err.println("defaultConnector() is: " + dflt +
274                 ", expected:" + expected);
275             failures++;
276         } else {
277             System.out.println("Okay");
278         }
279 
280         compare(attachingConnectors(), vmm.attachingConnectors());
281         compare(listeningConnectors(), vmm.listeningConnectors());
282         compare(launchingConnectors(), vmm.launchingConnectors());
283 
284         // test results
285         if (failures > 0) {
286             System.out.println("");
287             throw new RuntimeException(failures + " test(s) failed");
288         }
289     }
290 }